#include <stdint.h>

#include "vicl.h"

VixToolsState query_virtual_machine_power_state(int idx)
{
    VixToolsState powerState = 0;

    // Test the power state.
    err = Vix_GetProperties(vmachine[idx].handle,
                            VIX_PROPERTY_VM_POWER_STATE,
                            &powerState,
                            VIX_PROPERTY_NONE);

    if(VIX_OK != err) 
    {
        VICL_ERROR("query_virtual_machine_power_state(%u) failed {%x}", idx, err);
        for(;;);
        return -1;
    }    
    
    return powerState;
}


static int power_on_virtual_machine(int idx)
{
    if(idx >= MAX_VMS)
        return -1;
        
    if(vmachine[idx].usable == false)
        return -1;
        
    jobHandle = VixVM_PowerOn(vmachine[idx].handle,
                              VIX_VMPOWEROP_NORMAL, // powerOnOptions,
                              VIX_INVALID_HANDLE, // propertyListHandle,
                              NULL, // callbackProc,
                              NULL); // clientData

    err = VixJob_Wait(jobHandle,
                      VIX_PROPERTY_NONE);
    
    if(VIX_OK != err)
    {
        VICL_ERROR("POWER_ON: VIX_VMPOWEROP_NORMAL failed!");
        return -1;
    }
    
    Vix_ReleaseHandle(jobHandle);
    
    return 0;
}

static int power_off_virtual_machine(int idx)
{
    if(idx >= MAX_VMS)
        return -1;
        
    if(vmachine[idx].usable == false)
        return -1;
        
    jobHandle = VixVM_PowerOff(vmachine[idx].handle,
                               VIX_VMPOWEROP_FROM_GUEST, // Allow the guest OS to shut down gracefully
                               NULL,                     // callbackProc,
                               NULL);                    // clientData

    err = VixJob_Wait(jobHandle,
                      VIX_PROPERTY_NONE);
    
    if(VIX_OK != err)
    {
        VICL_ERROR("POWER_OFF: VIX_VMPOWEROP_FROM_GUEST failed, starting hardware power-off");
    
        jobHandle = VixVM_PowerOff(vmachine[idx].handle,
                                   VIX_VMPOWEROP_NORMAL,    // Power-off at the hardware level
                                   NULL,                    // callbackProc,
                                   NULL);                   // clientData

        err = VixJob_Wait(jobHandle,
                          VIX_PROPERTY_NONE);
                          
        if(VIX_OK != err)
        {
            VICL_ERROR("POWER_OFF: VIX_VMPOWEROP_NORMAL failed, VM is still running!");
            return -1;
        }
    }

    Vix_ReleaseHandle(jobHandle);
    
    return 0;
}

static int reset_virtual_machine(int idx)
{
    if(idx >= MAX_VMS)
        return -1;
        
    if(vmachine[idx].usable == false)
        return -1;
        
    jobHandle = VixVM_Reset(vmachine[idx].handle,
                            VIX_VMPOWEROP_NORMAL, // powerOptions (hard reset),
                            NULL,                 // callbackProc,
                            NULL);                // clientData

    err = VixJob_Wait(jobHandle,
                      VIX_PROPERTY_NONE);
    
    if(VIX_OK != err)
    {
        VICL_ERROR("RESET: VIX_VMPOWEROP_NORMAL failed, VM was probably not running!");
        return -1;
    }
    
    Vix_ReleaseHandle(jobHandle);
    
    return 0;
}

static int pause_virtual_machine(int idx)
{
    if(idx >= MAX_VMS)
        return -1;
        
    if(vmachine[idx].usable == false)
        return -1;
        
    jobHandle = VixVM_Pause(vmachine[idx].handle,
                            0,                  // options
                            VIX_INVALID_HANDLE, // propertyListHandle
                            NULL,               // callbackProc
                            NULL);              // clientData


    err = VixJob_Wait(jobHandle,
                      VIX_PROPERTY_NONE);
    
    if(VIX_OK != err)
    {
        VICL_ERROR("PAUSE: failed, error 0x%x", err);
        return -1;
    }
    
    Vix_ReleaseHandle(jobHandle);
    
    return 0;
}

static int suspend_virtual_machine(int idx)
{
    if(idx >= MAX_VMS)
        return -1;
        
    if(vmachine[idx].usable == false)
        return -1;
        
    jobHandle = VixVM_Suspend(vmachine[idx].handle,
                              0,                  // options
                              NULL,               // callbackProc
                              NULL);              // clientData


    err = VixJob_Wait(jobHandle,
                      VIX_PROPERTY_NONE);
    
    if(VIX_OK != err)
    {
        VICL_ERROR("SUSPEND: failed, error 0x%x", err);
        return -1;
    }
    
    Vix_ReleaseHandle(jobHandle);
    
    return 0;
}

static int resume_virtual_machine(int idx)
{
    if(idx >= MAX_VMS)
        return -1;
        
    if(vmachine[idx].usable == false)
        return -1;
        
    jobHandle = VixVM_Unpause(vmachine[idx].handle,
                              0,                  // options
                              VIX_INVALID_HANDLE, // propertyListHandle
                              NULL,               // callbackProc
                              NULL);              // clientData


    err = VixJob_Wait(jobHandle,
                      VIX_PROPERTY_NONE);
    
    if(VIX_OK != err)
    {
        VICL_ERROR("RESUME: failed, error 0x%x", err);
        return -1;
    }
    
    Vix_ReleaseHandle(jobHandle);
    
    return 0;
}

int list_power_options(int idx)
{
    VixToolsState powerState;
    
    VICL_STATUS("Querying the VM's power state");
    if((powerState = query_virtual_machine_power_state(idx)) == -1)
        return -1;
    
    // VIX_POWERSTATE_* are all masks for the powerState, there may be multiple bits set
    
    if(powerState & VIX_POWERSTATE_PAUSED){
        VICL_INFO("%s is currently paused", vmachine[idx].path); }
    else if(powerState & VIX_POWERSTATE_RESUMING){
        VICL_INFO("%s is currently resuming", vmachine[idx].path); }
    else if(powerState & VIX_POWERSTATE_POWERING_OFF){
        VICL_INFO("%s is currently powering off", vmachine[idx].path); }
    else if(powerState & VIX_POWERSTATE_POWERED_OFF){
        VICL_INFO("%s is currently powered off", vmachine[idx].path); }
    else if(powerState & VIX_POWERSTATE_POWERING_ON){
        VICL_INFO("%s is currently powering on", vmachine[idx].path); }
    else if(powerState & VIX_POWERSTATE_POWERED_ON){
        VICL_INFO("%s is currently powered on", vmachine[idx].path); }
    else if(powerState & VIX_POWERSTATE_SUSPENDING){
        VICL_INFO("%s is currently suspending", vmachine[idx].path); }
    else if(powerState & VIX_POWERSTATE_SUSPENDED){
        VICL_INFO("%s is currently suspended", vmachine[idx].path); }
    else if(powerState & VIX_POWERSTATE_RESETTING){
        VICL_INFO("%s is currently resetting", vmachine[idx].path); }
    else
    {
        VICL_ERROR("Unknown power state %u!", powerState);
        for(;;);
        return -1;
    }
    
    if(powerState & VIX_POWERSTATE_TOOLS_RUNNING){
        VICL_INFO("Guest tools are active"); }
    else{
        VICL_INFO("Guest tools are inactive"); }

    return 0;
}

int virtual_machine_power_options(int idx)
{
    VixToolsState powerState;
    int tmp;
  
    while(1)
    {
        VICL_INFO_RESET();
        if(list_power_options(idx) == -1)
            return -1;   
            
        VICL_INFO(" ");
        VICL_INFO("[%c]: Power ON", vmachine_ids[0]);
        VICL_INFO("[%c]: Power OFF", vmachine_ids[1]);
        VICL_INFO("[%c]: Reset", vmachine_ids[2]);
        VICL_INFO("[%c]: Pause", vmachine_ids[3]);
        VICL_INFO("[%c]: Suspend", vmachine_ids[4]);
        VICL_INFO("[%c]: Resume", vmachine_ids[5]);
        
        VICL_STATUS("Choose a power option");  
          
    bypass_msg1:        
        VICL_TITLE("Power Options Menu");
        while((keypress = getch()) == -1){}
                        
        if(keypress == '0')
            tmp = power_on_virtual_machine(idx);
        else if(keypress == '1')
        {
            VICL_STATUS("Querying the VM's power state");
            if((powerState = query_virtual_machine_power_state(idx)) == -1)
                return -1;
            if(powerState & (VIX_POWERSTATE_POWERED_OFF | VIX_POWERSTATE_POWERING_OFF))
            {
                VICL_ERROR("The VM is already powered/powering off");
               goto bypass_msg1;
            }
            else if(powerState & VIX_POWERSTATE_SUSPENDED)
            {
                VICL_ERROR("The VM must be powered on");
                goto bypass_msg1;
            }
            tmp = power_off_virtual_machine(idx);
        }
        else if(keypress == '2')
        {
            VICL_STATUS("Querying the VM's power state");
            if((powerState = query_virtual_machine_power_state(idx)) == -1)
                return -1;
            if(powerState & VIX_POWERSTATE_POWERED_OFF)
            {
                VICL_ERROR("Reset can not occur while the VM is powered off");
                goto bypass_msg1;
            }
            tmp = reset_virtual_machine(idx);
        }
        else if(keypress == '3')
        {
            VICL_STATUS("Querying the VM's power state");
            if((powerState = query_virtual_machine_power_state(idx)) == -1)
                return -1;
            if(powerState & VIX_POWERSTATE_PAUSED)
            {
                VICL_ERROR("The VM is already paused");
                goto bypass_msg1;
            }
            tmp = pause_virtual_machine(idx);
        }
        else if(keypress == '4')
        {
            VICL_STATUS("Querying the VM's power state");
            if((powerState = query_virtual_machine_power_state(idx)) == -1)
                return -1;
            if(powerState & VIX_POWERSTATE_PAUSED)
            {
                VICL_ERROR("The VM is already suspended");
                goto bypass_msg1;
            }
            tmp = suspend_virtual_machine(idx);
        }
        else if(keypress == '5')
        {
            VICL_STATUS("Querying the VM's power state");
            if((powerState = query_virtual_machine_power_state(idx)) == -1)
                return -1;
            if(!(powerState & VIX_POWERSTATE_PAUSED))
            {
                VICL_ERROR("The VM is not paused");
                goto bypass_msg1;
            }
            tmp = resume_virtual_machine(idx);
        }
        
        else if(keypress == 'h'){
            vicl_info_help2();
            goto bypass_msg1;
        }  
        
        else if(keypress == 'l'){
            // re-list the power options
        }
            
        else if(keypress == 'q'){
            vicl_info_help1();
            break;
        }
        else
            goto bypass_msg1;
        
        if(tmp == -1)
            return -1;
    }
    
    return 0;
}






